const PENDING = 'pending'; // 等待 状态
const FULFILLED = 'fulfilled'; // 成功 状态
const REJECTED = 'rejected'; // 失败 状态

class myPromise {
  constructor(executor) {
    try {
      executor(this.resolve.bind(this), this.reject.bind(this));
    } catch (e) {
      this.reject(e);
    }
  }
  // 当前的状态
  state = PENDING;
  // 结果值
  result = undefined;
  // 成功回调
  successCallbackList = [];
  // 失败回调
  failCallbackList = [];

  resolve(val) {
    // 状态不是 pending 就直接返回
    if (this.state !== PENDING) return;
    // 修改状态为成功状态
    this.state = FULFILLED;
    // 绑定成功结果
    this.result = val;

    this._nextTick(() => {
      // 多次的then需要按顺序执行成功的回调函数
      while (this.successCallbackList.length) this.successCallbackList.shift()(this.result);
    });
  }

  reject(val) {
    // 状态不是 pending 就直接返回
    if (this.state !== PENDING) return;
    // 修改状态为失败状态
    this.state = REJECTED;
    // 绑定失败结果
    this.result = val;

    this._nextTick(() => {
      // 多次的then需要按顺序执行失败的回调函数
      while (this.failCallbackList.length) this.failCallbackList.shift()(this.result);
    });
  }

  then(successCb, failCb) {
    // 参数处理
    successCb = successCb ? successCb : (value) => value;
    failCb = failCb
      ? failCb
      : (errStr) => {
          throw errStr;
        };
    const thenPromise = new myPromise((thenResolve, thenReject) => {
      this.successCallbackList.push((thenResult) => {
        try {
          // 执行成功回调函数，拿到返回值
          thenResult = successCb(thenResult);
          // 如果thenResult 是一个myPromise对象
          if (thenResult instanceof myPromise) {
            // thenResolve 需要拿到thenResult这个myPromise对象的result
            return thenResult.then(thenResolve, thenReject);
          }
          // resolve出这个值，链式调用的时候后面的then就可以拿到了
          thenResolve(thenResult);
        } catch (e) {
          thenReject(e);
        }
      });

      this.failCallbackList.push((thenResult) => {
        try {
          // 执行失败回调函数，拿到返回值
          thenResult = failCb(thenResult);
          // 如果thenResult 是一个myPromise对象
          if (thenResult instanceof myPromise) {
            // thenResolve 需要拿到thenResult这个myPromise对象的result
            return thenResult.then(thenResolve, thenReject);
          }
          // 失败函数的返回值是被下一个then成功回调接收的  这里需要执行thenResolve
          thenResolve(thenResult);
        } catch (e) {
          thenReject(e);
        }
      });
    });
    return thenPromise;
  }

  static all(array) {
    return new myPromise((resolve, reject) => {
      const arrayLen = array.length; // 数组的长度
      const res = []; //返回结果
      let fulfilledNum = 0; //成功的个数

      function addData(index, value) {
        // 顺序一致需要采用索引赋值而不是push
        res[index] = value;
        // 记录成功的个数 只有全部成功了 all 才 resolve
        fulfilledNum += 1;
        if (fulfilledNum === arrayLen) {
          resolve(res);
        }
      }
      array.forEach((item, index) => {
        if (item instanceof myPromise) {
          // myPromise 对象
          item.then(
            (val) => addData(index, val),
            (err) => reject(err)
          );
        } else {
          // 其他情况
          addData(index, item);
        }
      });
    });
  }

  finally(cb) {
    return this.then(
      // value 是 自己的resolve执行的时候传过来的自己的结果
      (value) => myPromise.resolve(cb()).then(() => value),
      // 包了一层myPromise.resolve 是为了等待cb函数返回的promise状态改变之后再返回 自己的value
      (err) =>
        myPromise.resolve(cb()).then(() => {
          throw err;
        })
    );
  }

  catch(failCb) {
    return this.then(undefined, failCb);
  }

  static resolve(value) {
    if (value instanceof myPromise) return value;
    return new myPromise((resolve) => resolve(value));
  }

  static reject(err) {
    if (err instanceof myPromise) return err;
    return new myPromise((resolve, reject) => reject(err));
  }

  // Promise -> MutationObserver -> setImmediate -> setTimeout
  _nextTick(cb) {
    // 执行回调函数
    const p = Promise.resolve();
    p.then(cb);
    // -------
    // MutationObserver 实现微任务
    // let ob = new MutationObserver(() => {
    //   cb();
    //   // 用完销毁
    //   ob.disconnect();
    //   ob = null;
    // });
    // ob.observe(document.body, { attributes: true });
    // document.body.setAttribute('_yl', Math.random());
    // -------
    // setTimeout 实现宏任务
    // setTimeout(cb, 0);
  }
}
